package com.cy.shiro;

import com.cy.model.Account;
import com.cy.model.AccountRole;
import com.cy.model.Menu;
import com.cy.model.User;
import com.cy.model.dingtalk.AccountMapDingding;
import com.cy.utils.Encodes;
import com.google.common.collect.Lists;
import jodd.util.StringUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class SERealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
        List<String> roles = shiroUser.getRoles();
        List<String> permissions = shiroUser.getRolesKey();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);
        info.addRoles(roles);
        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        QyUsernamePasswordToken token = (QyUsernamePasswordToken) authcToken;

        //限制用户只允许一处登录
        /*Cache cache = CacheManager.getCacheManager("shiro").getCache("shiro-activeSessionCache");
        Map<Object,Element> all = cache.getAll(cache.getKeys());
        for (Map.Entry<Object, Element> entry : all.entrySet()){
            Session session = (Session) entry.getValue().getObjectValue();
            PrincipalCollection principalCollection = (PrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if (principalCollection != null){
                ShiroUser shiroUser = (ShiroUser) principalCollection.getPrimaryPrincipal();
                if ("account".equals(token.getType())){
                    Account account = Account.dao.getByAccount(token.getUsername());
                    if (account.getAccountId().equals(shiroUser.getId())){
                        throw new ConcurrentAccessException();
                    }
                } else if ("user".equals(token.getType())){
                    User user = User.dao.findByMobile(token.getUsername());
                    if (user.getUserId().equals(shiroUser.getId())){
                        throw new ConcurrentAccessException();
                    }
                }
            }
        }*/

        if (token != null) {
            if ("account".equals(token.getType())){
                Account user = Account.dao.getByAccount(token.getUsername());
                if (user == null) {
                    throw new UnknownAccountException();
                }
                if (user.getStatus() != 1) {
                    throw new DisabledAccountException();
                }
                byte[] salt = Encodes.decodeHex(user.getSalt());

                Set<String> permissions = new HashSet<>();
                List<AccountRole> roles = user.getRoles();
                List<String> roleCodes = new ArrayList<>(roles.size());
                for (AccountRole role : roles){
                    if (role.getStatus() == 1){
                        roleCodes.add(role.getCode());
                        for (Menu menu : Menu.dao.findByRole(role.getId())){
                            if (StringUtil.isNotBlank(menu.getUrl()) && menu.getUrl().lastIndexOf(".jsp") == -1){
                                permissions.add(menu.getUrl()+ ":"+ menu.getMethod());
                            }
                        }
                    }
                }

                AccountMapDingding amd = AccountMapDingding.dao.findByAccount(user.getAccountId());
                if (amd != null)
                    user.put("dingUserId", amd.getDingUserId());

                ShiroUser shiroUser = new ShiroUser(user);
                shiroUser.setRolesKey(Lists.newArrayList(permissions));
                shiroUser.setRoles(roleCodes);

                return new SimpleAuthenticationInfo(shiroUser, user.getPassword(), ByteSource.Util.bytes(salt), getName());
            }else if ("user".equals(token.getType())){
                User user = User.dao.findByMobile(token.getUsername());
                if (user == null) {
                    throw new UnknownAccountException();
                }
                if (user.getStatus() != 1) {
                    throw new DisabledAccountException();
                }
                byte[] salt = Encodes.decodeHex(user.getSalt());

                return new SimpleAuthenticationInfo(new ShiroUser(user), user.getPassword(), ByteSource.Util.bytes(salt), getName());
            }else{
                throw new UnknownAccountException();
            }
        } else {
            throw new UnknownAccountException();
        }
    }

}
